﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using Common.Utilities;
using Workflows.Components.Entities.Distances;

namespace Workflows.Components.Entities
{
    public delegate void AttributeMetaDataAdded(AttributeMetaData attrMetaData);

    public partial class NewAttributeComparer : Form
    {
        private Dictionary<string, IAttributeDistanceCalcutor> _Comparers;
        private List<string> _FieldNames;
        public event AttributeMetaDataAdded OnAttributeMetaDataAdded;

        public NewAttributeComparer()
        {
            InitializeComponent();
        }

        private void NewAttributeComparer_Load(object sender, EventArgs e)
        {
            this.cbo_AttrTypes.Items.Clear();
            for (int i = 0; i <= 4;i++)
            {
                AttributeType attrType = (AttributeType) i;
                this.cbo_AttrTypes.Items.Add(attrType.ToString());
            }

                this._Comparers = new Dictionary<string, IAttributeDistanceCalcutor>();
            string binFolderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            DirectoryInfo dirInfo=new DirectoryInfo(binFolderPath);
            FileInfo[] dllInfos = dirInfo.GetFiles("*.dll", SearchOption.TopDirectoryOnly);
            this.cbo_Comparer.Items.Clear();
            foreach(FileInfo dllInfo in dllInfos)
            {
                if(dllInfo.Name.ToLower().StartsWith("discoverylogic") || 
                    dllInfo.Name.ToLower().StartsWith("workflow"))
                {
                    Assembly assembly = Assembly.LoadFile(dllInfo.FullName);
                    Type[] types = assembly.GetTypes();
                    foreach(Type type in types)
                    {
                        if(type.GetInterface(typeof(IAttributeDistanceCalcutor).FullName)!=null)
                        {
                            IAttributeDistanceCalcutor comparer =
                                (IAttributeDistanceCalcutor) Activator.CreateInstance(type) as IAttributeDistanceCalcutor;
                            if(comparer !=null)
                            {
                                this._Comparers.Add(type.FullName, comparer);
                                this.cbo_Comparer.Items.Add(type.FullName);
                            }
                        }
                    }
                }
            }
        }

        public void LoadSettings(IAttributeDistanceCalcutor comparer, List<string> fieldNames)
        {
            this._FieldNames = fieldNames;
            for(int i=0;i<this.cbo_Comparer.Items.Count;i++)
            {
                if(this.cbo_Comparer.Items[i].ToString()==comparer.GetType().FullName)
                {
                    this.cbo_Comparer.SelectedIndex = i;
                    break;
                }
            }
            
        }

        private void cbo_Comparer_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(this.cbo_Comparer.SelectedIndex>=0)
            {
                IAttributeDistanceCalcutor comparer = this._Comparers[this.cbo_Comparer.SelectedItem.ToString()];
                this.dv_Attr.Rows.Clear();
                foreach(string argName in comparer.ArgumentNames)
                {
                    DataGridViewRow dr = new DataGridViewRow();
                    DataGridViewTextBoxCell cellArg=new DataGridViewTextBoxCell();
                    cellArg.Value = argName;
                    dr.Cells.Add(cellArg);

                    DataGridViewComboBoxCell cellFieldName = new DataGridViewComboBoxCell();
                    foreach(string fieldName in this._FieldNames)
                    {
                        cellFieldName.Items.Add(fieldName);
                    }
                    dr.Cells.Add(cellFieldName);

                    this.dv_Attr.Rows.Add(dr);
                }

                this.dv_Settings.Rows.Clear();
                if(comparer.ComparerSettings!=null && comparer.ComparerSettings.Count>0)
                {
                    foreach(string name in comparer.ComparerSettings.Keys)
                    {
                        DataGridViewRow dr = new DataGridViewRow();
                        DataGridViewTextBoxCell cellName=new DataGridViewTextBoxCell();
                        cellName.Value = name;
                        dr.Cells.Add(cellName);
                        DataGridViewTextBoxCell cellVal=new DataGridViewTextBoxCell();
                        cellVal.Value = comparer.ComparerSettings[name];
                        dr.Cells.Add(cellVal);
                        this.dv_Settings.Rows.Add(dr);
                    }
                }
            }
        }

        private void btn_OK_Click(object sender, EventArgs e)
        {
            if(this.cbo_Comparer.SelectedIndex>=0 && this.cbo_AttrTypes.SelectedIndex>=0)
            {
                IAttributeDistanceCalcutor comparer = this._Comparers[this.cbo_Comparer.SelectedItem.ToString()];
                string typeName = comparer.GetType().FullName;
                string assemblyName = comparer.GetType().Assembly.GetName().Name;
                AttributeType attrType = (AttributeType) this.cbo_AttrTypes.SelectedIndex;
                double posW = (double) this.num_PosW.Value;
                double negW = (double) this.num_NegW.Value;

                Dictionary<string, string> bindings = new Dictionary<string, string>();
                foreach(DataGridViewRow dr in this.dv_Attr.Rows)
                {
                    if(!dr.IsNewRow && dr.Cells[0].Value !=null && dr.Cells[1].Value !=null)
                    {
                        string argName = dr.Cells[0].Value.ToString();
                        string fieldName = dr.Cells[1].Value.ToString();
                        bindings.Add(argName,fieldName);
                    }
                }

                AttributeMetaData attrMetaData = null;
                DataProviderType dbProvider = DataProviderType.MSSQL;
                dbProvider = (DataProviderType)this.cbo_DbProvider.SelectedIndex;
                string connStr = string.Empty;
                string selectSql = string.Empty;
                if (this.ck_UseQuery.Checked)
                {
                    connStr = this.txt_ConnStr.Text;
                    selectSql = this.rt_SelectSql.Text;
                }
                Dictionary<string, string> comparerSettings = new Dictionary<string, string>();
                foreach(DataGridViewRow dr in this.dv_Settings.Rows)
                {
                    if(!dr.IsNewRow && dr.Cells[0].Value !=null)
                    {
                        string name = (string) dr.Cells[0].Value;
                        string value = (string) dr.Cells[1].Value;
                        comparerSettings.Add(name,value);
                    }
                }
                if(attrType==AttributeType.CompositeAttribute)
                {
                    attrMetaData =
                        new AttributeMetaData(
                            bindings, assemblyName, typeName, comparerSettings,
                            posW, negW, this.ck_UseQuery.Checked,
                            dbProvider, connStr, selectSql);
                }
                else
                {
                    string fieldName = bindings.Values.ToArray()[0];
                    attrMetaData =
                        new AttributeMetaData(
                            fieldName, attrType, assemblyName, typeName,
                            comparerSettings, posW, negW, this.ck_UseQuery.Checked,
                            dbProvider, connStr, selectSql);
                }

                if (this.OnAttributeMetaDataAdded != null)
                    this.OnAttributeMetaDataAdded(attrMetaData);

                this.Close();
            }
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void ck_UseQuery_CheckedChanged(object sender, EventArgs e)
        {
            if(this.ck_UseQuery.Checked)
            {
                this.txt_ConnStr.Enabled = true;
                this.rt_SelectSql.Enabled = true;
                this.btn_Update.Enabled = true;
                this.cbo_DbProvider.Enabled = true;
            }
            else
            {
                this.txt_ConnStr.Enabled = false;
                this.rt_SelectSql.Enabled = false;
                this.btn_Update.Enabled = false;
                this.cbo_DbProvider.Enabled = false;

                foreach(DataGridViewRow dr in this.dv_Attr.Rows)
                {
                    if(!dr.IsNewRow)
                    {
                        DataGridViewComboBoxCell cellTgt = (DataGridViewComboBoxCell) dr.Cells[1];
                        string cellValue = null;
                        if(cellTgt.Value !=null)
                            cellValue = (string) cellTgt.Value;
                        cellTgt.Value = null;
                        foreach(string fieldName in this._FieldNames)
                        {
                            cellTgt.Items.Add(fieldName);
                            if(cellValue !=null && fieldName==cellValue)
                                cellTgt.Value = fieldName;
                        }
                    }
                }
            }
        }

        private void btn_Update_Click(object sender, EventArgs e)
        {
            if(!string.IsNullOrEmpty(this.txt_ConnStr.Text) && !string.IsNullOrEmpty(this.rt_SelectSql.Text))
            {
                DataProviderType dbProvider = (DataProviderType) this.cbo_DbProvider.SelectedIndex;
                string connStr = this.txt_ConnStr.Text;
                string sql = this.rt_SelectSql.Text;
                if(sql.IndexOf("{0}")>0)
                {
                    sql = sql.Replace("{0}", "1");
                }
                TableColumn[] cols = DbUtil.GetTableColumns(dbProvider, connStr, sql);

                foreach (DataGridViewRow dr in this.dv_Attr.Rows)
                {
                    if (!dr.IsNewRow)
                    {
                        DataGridViewComboBoxCell cellTgt = (DataGridViewComboBoxCell)dr.Cells[1];
                        string cellValue = null;
                        if (cellTgt.Value != null)
                            cellValue = (string)cellTgt.Value;
                        cellTgt.Value = null;
                        cellTgt.Items.Clear();
                        if (cols != null && cols.Length > 0)
                        {
                            foreach (TableColumn col in cols)
                            {
                                cellTgt.Items.Add(col.ColumnName);
                                if (cellValue != null && col.ColumnName == cellValue)
                                    cellTgt.Value = col.ColumnName;
                            }
                        }
                    }
                }
            }
        }
    }
}
